﻿#include <windows.h>
#include <iostream>
#include "SimpleIni.h"

#define INJECTED_KEY 0x12345678

HHOOK hHook = NULL;
CSimpleIniA g_ini;
std::map<std::string, uint32_t> g_KeyMap;

// 低级键盘钩子回调
LRESULT CALLBACK KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
{
    if (nCode == HC_ACTION)
    {
        KBDLLHOOKSTRUCT* p = (KBDLLHOOKSTRUCT*)lParam;

        // 如果是我们自己注入的消息，直接放行
        if (p->dwExtraInfo == INJECTED_KEY)
        {
            return CallNextHookEx(hHook, nCode, wParam, lParam);
        }

        // printf("vkcode = 0x%x \n", p->vkCode);

        // 在一个section获取所有keys
        CSimpleIniA::TNamesDepend keys;
        g_ini.GetAllKeys("Keys", keys);

        CSimpleIniA::TNamesDepend::const_iterator it;
        for (it = keys.begin(); it != keys.end(); ++it)
        {
            // printf("vkcode name = %s \n", it->pItem);

            auto itKey = g_KeyMap.find(it->pItem);
            if (itKey != g_KeyMap.end())
            {
                // 判断按下的是 SPACE
                if (p->vkCode == itKey->second)
                {
                    const char* value = g_ini.GetValue("Keys", it->pItem, nullptr);

                    if (strcmp(value, it->pItem) == 0)
                    {
                        break;
                    }

                    auto itKeyReplace = g_KeyMap.find(value);
                    if (itKeyReplace != g_KeyMap.end())
                    {
                        // printf("to vkcode = 0x%x \n", itKeyReplace->second);

                        // 把消息改为 F1
                        INPUT input = { 0 };
                        input.type = INPUT_KEYBOARD;
                        input.ki.wVk = itKeyReplace->second;
                        input.ki.wScan = 0;
                        input.ki.dwFlags = (wParam == WM_KEYUP || wParam == WM_SYSKEYUP) ? KEYEVENTF_KEYUP : 0;
                        input.ki.time = 0;
                        input.ki.dwExtraInfo = INJECTED_KEY;
                        SendInput(1, &input, sizeof(INPUT));

                        // 返回 1 表示拦截，不再传递 SPACE
                        return 1;
                    }
                }
            }

        }
    }

    return CallNextHookEx(hHook, nCode, wParam, lParam);
}

// 初始化g_KeyMap
void InitKeyMap()
{
    // F1 - F12
    g_KeyMap["F1"] = VK_F1;
    g_KeyMap["F2"] = VK_F2;
    g_KeyMap["F3"] = VK_F3;
    g_KeyMap["F4"] = VK_F4;
    g_KeyMap["F5"] = VK_F5;
    g_KeyMap["F6"] = VK_F6;
    g_KeyMap["F7"] = VK_F7;
    g_KeyMap["F8"] = VK_F8;
    g_KeyMap["F9"] = VK_F9;
    g_KeyMap["F10"] = VK_F10;
    g_KeyMap["F11"] = VK_F11;
    g_KeyMap["F12"] = VK_F12;

    // 0 - 9
    g_KeyMap["0"] = '0';
    g_KeyMap["1"] = '1';
    g_KeyMap["2"] = '2';
    g_KeyMap["3"] = '3';
    g_KeyMap["4"] = '4';
    g_KeyMap["5"] = '5';
    g_KeyMap["6"] = '6';
    g_KeyMap["7"] = '7';
    g_KeyMap["8"] = '8';
    g_KeyMap["9"] = '9';

    // 26个字母
    g_KeyMap["q"] = 'Q';
    g_KeyMap["w"] = 'W';
    g_KeyMap["e"] = 'E';
    g_KeyMap["r"] = 'R';
    g_KeyMap["t"] = 'T';
    g_KeyMap["y"] = 'Y';
    g_KeyMap["u"] = 'U';
    g_KeyMap["i"] = 'I';
    g_KeyMap["o"] = 'O';
    g_KeyMap["p"] = 'P';
    g_KeyMap["a"] = 'A';
    g_KeyMap["s"] = 'S';
    g_KeyMap["d"] = 'D';
    g_KeyMap["f"] = 'F';
    g_KeyMap["g"] = 'G';
    g_KeyMap["h"] = 'H';
    g_KeyMap["j"] = 'J';
    g_KeyMap["k"] = 'K';
    g_KeyMap["l"] = 'L';
    g_KeyMap["z"] = 'Z';
    g_KeyMap["x"] = 'X';
    g_KeyMap["c"] = 'C';
    g_KeyMap["v"] = 'V';
    g_KeyMap["b"] = 'B';
    g_KeyMap["n"] = 'N';
    g_KeyMap["m"] = 'M';

    // 小键盘0 - 9
    g_KeyMap["num0"] = VK_NUMPAD0;
    g_KeyMap["num1"] = VK_NUMPAD1;
    g_KeyMap["num2"] = VK_NUMPAD2;
    g_KeyMap["num3"] = VK_NUMPAD3;
    g_KeyMap["num4"] = VK_NUMPAD4;
    g_KeyMap["num5"] = VK_NUMPAD5;
    g_KeyMap["num6"] = VK_NUMPAD6;
    g_KeyMap["num7"] = VK_NUMPAD7;
    g_KeyMap["num8"] = VK_NUMPAD8;
    g_KeyMap["num9"] = VK_NUMPAD9;

    g_KeyMap["space"] = VK_SPACE;

    // 其他
    g_KeyMap["esc"] = VK_ESCAPE;
    g_KeyMap["backtick"] = '`';
    g_KeyMap["backspace"] = VK_BACK;
    g_KeyMap["tab"] = VK_TAB;
    g_KeyMap["lbracket"] = '[';
    g_KeyMap["rbracket"] = ']';
    g_KeyMap["enter"] = VK_RETURN;
    g_KeyMap["capslock"] = VK_CAPITAL;
    g_KeyMap["semicolon"] = ';';
    g_KeyMap["apostrophe"] = 0x27;
    g_KeyMap["backslash"] = 0x5C;
    g_KeyMap["lshift"] = VK_LSHIFT;
    g_KeyMap["rshift"] = VK_RSHIFT;
    g_KeyMap["comma"] = ',';
    g_KeyMap["period"] = '.';
    g_KeyMap["slash"] = '/';
    g_KeyMap["lctrl"] = VK_LCONTROL;
    g_KeyMap["rctrl"] = VK_RCONTROL;
    g_KeyMap["lwin"] = VK_LWIN;
    g_KeyMap["rwin"] = VK_RWIN;
    g_KeyMap["lalt"] = VK_LMENU;
    g_KeyMap["ralt"] = VK_RMENU;

    g_KeyMap["printscrren"] = VK_SNAPSHOT;
    g_KeyMap["scrolllock"] = VK_SCROLL;
    g_KeyMap["pause"] = VK_PAUSE;
    g_KeyMap["insert"] = VK_INSERT;
    g_KeyMap["home"] = VK_HOME;
    g_KeyMap["pageup"] = VK_PRIOR;
    g_KeyMap["delete"] = VK_DELETE;
    g_KeyMap["end"] = VK_END;
    g_KeyMap["pagedown"] = VK_NEXT;

    g_KeyMap["up"] = VK_UP;
    g_KeyMap["down"] = VK_DOWN;
    g_KeyMap["left"] = VK_LEFT;
    g_KeyMap["right"] = VK_RIGHT;

    g_KeyMap["numlock"] = VK_NUMLOCK;
    g_KeyMap["numdiv"] = VK_DIVIDE;
    g_KeyMap["nummul"] = VK_MULTIPLY;
    g_KeyMap["numsubtract"] = VK_SUBTRACT;
    g_KeyMap["numadd"] = VK_ADD;
    g_KeyMap["numdecimal"] = VK_DECIMAL;
}

// 创建INI配置文件
void CreateIniConfig()
{
    g_ini.SetUnicode();

    SI_Error rc = g_ini.LoadFile("config.ini");
    if (rc == SI_OK)
    {
        // CSimpleIniA::TNamesDepend keys;
        // g_ini.GetAllKeys("Keys", keys);
        // 
        // CSimpleIniA::TNamesDepend::const_iterator it;
        // for (it = keys.begin(); it != keys.end(); ++it)
        // {
        //     const char* value = g_ini.GetValue("Keys", it->pItem, nullptr);
        //     printf("'%s' = '%s'\n", it->pItem, value);
        // }
        return;
    }

    // F1 - F12
    g_ini.SetValue("Keys", "F1", "F1");
    g_ini.SetValue("Keys", "F2", "F2");
    g_ini.SetValue("Keys", "F3", "F3");
    g_ini.SetValue("Keys", "F4", "F4");
    g_ini.SetValue("Keys", "F5", "F5");
    g_ini.SetValue("Keys", "F6", "F6");
    g_ini.SetValue("Keys", "F7", "F7");
    g_ini.SetValue("Keys", "F8", "F8");
    g_ini.SetValue("Keys", "F9", "F9");
    g_ini.SetValue("Keys", "F10", "F10");
    g_ini.SetValue("Keys", "F11", "F11");
    g_ini.SetValue("Keys", "F12", "F12");

    // 0 - 9
    g_ini.SetValue("Keys", "0", "0");
    g_ini.SetValue("Keys", "1", "1");
    g_ini.SetValue("Keys", "2", "2");
    g_ini.SetValue("Keys", "3", "3");
    g_ini.SetValue("Keys", "4", "4");
    g_ini.SetValue("Keys", "5", "5");
    g_ini.SetValue("Keys", "6", "6");
    g_ini.SetValue("Keys", "7", "7");
    g_ini.SetValue("Keys", "8", "8");
    g_ini.SetValue("Keys", "9", "9");

    // 26个字母
    g_ini.SetValue("Keys", "q", "q");
    g_ini.SetValue("Keys", "w", "w");
    g_ini.SetValue("Keys", "e", "e");
    g_ini.SetValue("Keys", "r", "r");
    g_ini.SetValue("Keys", "t", "t");
    g_ini.SetValue("Keys", "y", "y");
    g_ini.SetValue("Keys", "u", "u");
    g_ini.SetValue("Keys", "i", "i");
    g_ini.SetValue("Keys", "o", "o");
    g_ini.SetValue("Keys", "p", "p");
    g_ini.SetValue("Keys", "a", "a");
    g_ini.SetValue("Keys", "s", "s");
    g_ini.SetValue("Keys", "d", "d");
    g_ini.SetValue("Keys", "f", "f");
    g_ini.SetValue("Keys", "g", "g");
    g_ini.SetValue("Keys", "h", "h");
    g_ini.SetValue("Keys", "j", "j");
    g_ini.SetValue("Keys", "k", "k");
    g_ini.SetValue("Keys", "l", "l");
    g_ini.SetValue("Keys", "z", "z");
    g_ini.SetValue("Keys", "x", "x");
    g_ini.SetValue("Keys", "c", "c");
    g_ini.SetValue("Keys", "v", "v");
    g_ini.SetValue("Keys", "b", "b");
    g_ini.SetValue("Keys", "n", "n");
    g_ini.SetValue("Keys", "m", "m");

    // 小键盘0-9
    g_ini.SetValue("Keys", "num0", "num0");
    g_ini.SetValue("Keys", "num1", "num1");
    g_ini.SetValue("Keys", "num2", "num2");
    g_ini.SetValue("Keys", "num3", "num3");
    g_ini.SetValue("Keys", "num4", "num4");
    g_ini.SetValue("Keys", "num5", "num5");
    g_ini.SetValue("Keys", "num6", "num6");
    g_ini.SetValue("Keys", "num7", "num7");
    g_ini.SetValue("Keys", "num8", "num8");
    g_ini.SetValue("Keys", "num9", "num9");

    // 空格
    g_ini.SetValue("Keys", "space", "space");

    // 其他
    g_ini.SetValue("Keys", "esc", "esc");
    g_ini.SetValue("Keys", "backtick", "backtick");
    g_ini.SetValue("Keys", "backspace", "backspace");
    g_ini.SetValue("Keys", "tab", "tab");
    g_ini.SetValue("Keys", "lbracket", "lbracket");
    g_ini.SetValue("Keys", "rbracket", "rbracket");
    g_ini.SetValue("Keys", "enter", "enter");
    g_ini.SetValue("Keys", "capslock", "capslock");
    g_ini.SetValue("Keys", "semicolon", "semicolon");
    g_ini.SetValue("Keys", "apostrophe", "apostrophe");
    g_ini.SetValue("Keys", "backslash", "backslash");
    g_ini.SetValue("Keys", "lshift", "lshift");
    g_ini.SetValue("Keys", "rshift", "rshift");
    g_ini.SetValue("Keys", "comma", "comma");
    g_ini.SetValue("Keys", "period", "period");
    g_ini.SetValue("Keys", "slash", "slash");
    g_ini.SetValue("Keys", "lctrl", "lctrl");
    g_ini.SetValue("Keys", "rctrl", "rctrl");
    g_ini.SetValue("Keys", "lwin", "lwin");
    g_ini.SetValue("Keys", "rwin", "rwin");
    g_ini.SetValue("Keys", "lalt", "lalt");
    g_ini.SetValue("Keys", "ralt", "ralt");

    g_ini.SetValue("Keys", "printscrren", "printscrren");
    g_ini.SetValue("Keys", "scrolllock", "scrolllock");
    g_ini.SetValue("Keys", "pause", "pause");
    g_ini.SetValue("Keys", "insert", "insert");
    g_ini.SetValue("Keys", "home", "home");
    g_ini.SetValue("Keys", "pageup", "pageup");
    g_ini.SetValue("Keys", "delete", "delete");
    g_ini.SetValue("Keys", "end", "end");
    g_ini.SetValue("Keys", "pagedown", "pagedown");

    g_ini.SetValue("Keys", "up", "up");
    g_ini.SetValue("Keys", "down", "down");
    g_ini.SetValue("Keys", "left", "left");
    g_ini.SetValue("Keys", "right", "right");

    g_ini.SetValue("Keys", "numlock", "numlock");
    g_ini.SetValue("Keys", "numdiv", "numdiv");
    g_ini.SetValue("Keys", "nummul", "nummul");
    g_ini.SetValue("Keys", "numsubtract", "numsubtract");
    g_ini.SetValue("Keys", "numadd", "numadd");
    g_ini.SetValue("Keys", "numdecimal", "numdecimal");


    g_ini.SaveFile("config.ini");
}

void SendClipboardText(const std::wstring& text)
{
    if (OpenClipboard(NULL))
    {
        EmptyClipboard();
        HGLOBAL hGlob = GlobalAlloc(GMEM_FIXED, (text.size() + 1) * sizeof(wchar_t));
        memcpy(hGlob, text.c_str(), text.size() * sizeof(wchar_t));
        SetClipboardData(CF_UNICODETEXT, hGlob);
        CloseClipboard();
    }
}

void SimulateCtrlVAndEnter()
{
    INPUT inputs[8] = {};

    // Enter down
    inputs[0].type = INPUT_KEYBOARD;
    inputs[0].ki.wVk = VK_RETURN;

    // Enter up
    inputs[1].type = INPUT_KEYBOARD;
    inputs[1].ki.wVk = VK_RETURN;
    inputs[1].ki.dwFlags = KEYEVENTF_KEYUP;

    // Ctrl down
    inputs[2].type = INPUT_KEYBOARD;
    inputs[2].ki.wVk = VK_CONTROL;

    // V down
    inputs[3].type = INPUT_KEYBOARD;
    inputs[3].ki.wVk = 'V';

    // V up
    inputs[4].type = INPUT_KEYBOARD;
    inputs[4].ki.wVk = 'V';
    inputs[4].ki.dwFlags = KEYEVENTF_KEYUP;

    // Ctrl up
    inputs[5].type = INPUT_KEYBOARD;
    inputs[5].ki.wVk = VK_CONTROL;
    inputs[5].ki.dwFlags = KEYEVENTF_KEYUP;

    // Enter down
    inputs[6].type = INPUT_KEYBOARD;
    inputs[6].ki.wVk = VK_RETURN;

    // Enter up
    inputs[7].type = INPUT_KEYBOARD;
    inputs[7].ki.wVk = VK_RETURN;
    inputs[7].ki.dwFlags = KEYEVENTF_KEYUP;

    SendInput(8, inputs, sizeof(INPUT));
}

int main(int argc, char* argv[])
{
    if (argc > 1)
    {
        std::string strUsage = R"(
创建一个config.ini文件，将空格改为F1
[Keys]
space = F1
然后运行ModifyKey即可。

所有按键如下所示：
[Keys]
F1 = F1
F2 = F2
F3 = F3
F4 = F4
F5 = F5
F6 = F6
F7 = F7
F8 = F8
F9 = F9
F10 = F10
F11 = F11
F12 = F12
0 = 0
1 = 1
2 = 2
3 = 3
4 = 4
5 = 5
6 = 6
7 = 7
8 = 8
9 = 9
q = q
w = w
e = e
r = r
t = t
y = y
u = u
i = i
o = o
p = p
a = a
s = s
d = d
f = f
g = g
h = h
j = j
k = k
l = l
z = z
x = x
c = c
v = v
b = b
n = n
m = m
num0 = num0
num1 = num1
num2 = num2
num3 = num3
num4 = num4
num5 = num5
num6 = num6
num7 = num7
num8 = num8
num9 = num9
space = space
esc = esc
backtick = backtick
backspace = backspace
tab = tab
lbracket = lbracket
rbracket = rbracket
enter = enter
capslock = capslock
semicolon = semicolon
apostrophe = apostrophe
backslash = backslash
lshift = lshift
rshift = rshift
comma = comma
period = period
slash = slash
lctrl = lctrl
rctrl = rctrl
lwin = lwin
rwin = rwin
lalt = lalt
ralt = ralt
printscrren = printscrren
scrolllock = scrolllock
pause = pause
insert = insert
home = home
pageup = pageup
delete = delete
end = end
pagedown = pagedown
up = up
down = down
left = left
right = right
numlock = numlock
numdiv = numdiv
nummul = nummul
numsubtract = numsubtract
numadd = numadd
numdecimal = numdecimal
        )";

        for (int i = 1;i < argc;i++)
        {
            std::string strArgv = argv[i];
            if (strArgv == "-h")
            {
                std::cout << strUsage << std::endl;
                return 0;
            }
        }
    }

    // 创建INI配置文件
    CreateIniConfig();

    // 初始化g_KeyMap
    InitKeyMap();

    // 安装键盘钩子
    hHook = SetWindowsHookEx(WH_KEYBOARD_LL, KeyboardProc, GetModuleHandle(NULL), 0);
    if (!hHook) 
    {
        std::cerr << "Failed to install hook!" << std::endl;
        return 1;
    }

    // 注册热键
    if (!RegisterHotKey(NULL, 1, 0, 0x33))
    {
        MessageBox(NULL, L"热键注册失败", L"错误", MB_ICONERROR);
        return 1;
    }

    if (!RegisterHotKey(NULL, 2, 0, 0x34))
    {
        MessageBox(NULL, L"热键注册失败", L"错误", MB_ICONERROR);
        return 1;
    }

    std::cout << "running..." << std::endl;

    // 消息循环
    MSG msg;
    while (GetMessage(&msg, NULL, 0, 0))
    {
        if (msg.message == WM_HOTKEY)
        {
            switch (msg.wParam)
            {
            case 1:
                {
                    std::wstring shoutText = L"hg"; // 要喊的话
                    SendClipboardText(shoutText);
                    Sleep(100); // 等待剪贴板准备好
                    SimulateCtrlVAndEnter();
                    break;
                }

            case 2:
                {
                    std::wstring shoutText = L"hc"; // 要喊的话
                    SendClipboardText(shoutText);
                    Sleep(100); // 等待剪贴板准备好
                    SimulateCtrlVAndEnter();
                    break;
                }

            default:
                break;
            }
        }
        else
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }

    // 卸载钩子
    UnhookWindowsHookEx(hHook);
    return 0;
}
